#include "cservicebackend.h"

CServiceBackend::CServiceBackend(QObject *parent) : QObject(parent)
{
    //设置默认页面信息
    m_mainPageSetting.pageSize = "A4";
    //设置页边距，左、上、右、下，依次为27mm(319pix)、35mm(413pix)、27mm(319pix)、37mm(437pix),默认使用磅作为单位
    //    m_mainPageSetting.pageMarMargins = QMarginsF(27/25.4*72,20/25.4*72,27/25.4*72,20/25.4*72);
    m_mainPageSetting.pageMarMargins = QMarginsF(27,35,27,37);//用毫米作为单位

    m_mainPageSetting.isDoublePage = false;
    m_mainPageSetting.islandScape = false;
    m_mainPageSetting.isZhuangDing = false;
    m_mainPageSetting.h1Font = QFont("方正小标宋简体",22);
    m_mainPageSetting.h2Font = QFont("黑体",16);
    m_mainPageSetting.hcFont = QFont("仿宋_GB2312",16);
    m_mainPageSetting.ksFont = QFont("仿宋_GB2312",14);
    m_mainPageSetting.hJianju = 5;
    m_mainPageSetting.ppi = 300;
    //绘制起点
    m_xStart = 0;
    m_yStart = 0;
    //是否奇数页
    m_isOddPage = true;
    m_pPainter = new QPainter();
}

CServiceBackend::~CServiceBackend()
{
//    m_book->release();
//    delete m_pdfWriter;
}

QString CServiceBackend::getError()
{
    return  m_error;
}

void CServiceBackend::setError(QString error)
{
    m_error = error;
}

void CServiceBackend::setExcelFileName(QString name)
{
    m_excelFileName = name;
}

bool CServiceBackend::openExcelFile()
{
    //根据Excel的不同后缀确定调用的函数
    QString houzui = m_excelFileName.split(".").last();
    if(houzui == "xls")
        m_book = xlCreateBook();
    else if(houzui == "xlsx")
        m_book = xlCreateXMLBook();
    else {
        setError("你选择不是一个标准的Excel文件！");
        emit error();
        return false;
    }
    if(!m_book){
        setError(QString(m_book->errorMessage()));
        emit error();
        return false;
    }
    //载入Excel文件
    m_book->setKey(L"qwerasdf",L"windows-2028250e01c3eb0968b2676cadrfr1i6");
    bool ret = m_book->load(m_excelFileName.toStdWString().c_str());//把QString转为wchar_t*
    if(!ret){
        setError(QString(m_book->errorMessage()));
        emit error();
        return false;
    }
    //查找题库工作表
    m_sheet = NULL;
    for(int i = 0 ;i<m_book->sheetCount();i++){
        if(QString::fromStdWString(m_book->getSheetName(i)) == "题库"){
            m_sheet = m_book->getSheet(i);
            if(!m_sheet){
                setError(QString(m_book->errorMessage()));
                emit error();
                return false;
            }
            break;
        }
    }
    if(m_sheet == NULL){
        setError("没有找到名称为“题库”的工作表，请将题库所在工作表名称修改为“题库”！");
        emit error();
        return false;
    }
    //如果没有试题，要进行提醒
    if(m_sheet->lastRow()<4){
        //无题目
        setError("题库内没有试题，请添加试题后再尝试！");
        emit error();
        return false;
    }
    return true;
}

bool CServiceBackend::readItemBankMsg()
{
    int msgColumn = 1;//表示题型所在的列的列号
    //读取Excel文件数据
    bool ret = openExcelFile();
    if(!ret)
        return false;
    //初始化题库信息
    m_dTiXingList.clear();
    m_dxTiXingList.clear();
    m_pTiXingList.clear();
    m_tTiXingList.clear();
    m_jTiXingList.clear();
    m_itemBankMsg.clear();
    //Excel题库读取
    for(int row = 0;row<m_sheet->lastRow();row++){
        if(m_sheet->cellType(row,msgColumn) == CELLTYPE_STRING){
            const wchar_t* tiXing = m_sheet->readStr(row,msgColumn);//读取单元格字符串
            QString sTiXing = QString::fromStdWString(tiXing);//转化为字符串
            //添加题型行号到对应数组中
            if(sTiXing == "单选题")
                m_dTiXingList.append(row);
            else if(sTiXing == "多选题")
                m_dxTiXingList.append(row);
            else if(sTiXing == "判断题")
                m_pTiXingList.append(row);
            else if(sTiXing == "填空题")
                m_tTiXingList.append(row);
            else if(sTiXing == "简答题")
                m_jTiXingList.append(row);
            else
                continue;//如果是其他题型直接忽视
        }
    }
    //获取每种题型的数量
    m_itemBankMsg.insert("单选题",m_dTiXingList.count());
    m_itemBankMsg.insert("多选题",m_dxTiXingList.count());
    m_itemBankMsg.insert("判断题",m_pTiXingList.count());
    m_itemBankMsg.insert("填空题",m_tTiXingList.count());
    m_itemBankMsg.insert("简答题",m_jTiXingList.count());
    emit readReady();
    return true;
}

QVariantMap CServiceBackend::getItemBankMsg()
{
    return  m_itemBankMsg;
}
void CServiceBackend::appendTestPaperSet(QString testName, int testNum, double fenZhi)
{
    SetMessge temp;
    temp.m_TestName = testName;
    temp.m_testNum = testNum;
    temp.m_fenZhi = fenZhi;
    m_testPaperSet.append(temp);
}
void CServiceBackend::clearTestPaperSet()
{
    //    qDebug()<<"清除试卷设置信息";
    m_testPaperSet.clear();
}
void CServiceBackend::readPageSetting(QVariantMap map)
{
    m_mainPageSetting.pageSize = map["纸张"].toString();
    //设置页边距，左、上、右、下,使用毫米作为单位
    m_mainPageSetting.pageMarMargins =  QMarginsF(map["左边距"].toInt(),map["上边距"].toInt(),map["右边距"].toInt(),map["下边距"].toInt());
    m_mainPageSetting.isDoublePage = map["双面"].toBool();
    m_mainPageSetting.islandScape = map["横向页面"].toBool();
    m_mainPageSetting.isZhuangDing = map["侧面封装"].toBool();
    m_mainPageSetting.h1Font = QFont(map["主标题字体"].toString(),map["主标题字号"].toInt());
    m_mainPageSetting.h2Font = QFont(map["一级标题字体"].toString(),map["一级标题字号"].toInt());
    m_mainPageSetting.hcFont = QFont(map["正文字体"].toString(),map["正文字号"].toInt());
    m_mainPageSetting.ksFont = QFont(map["考生信息字体"].toString(),map["考生信息字号"].toInt());
    m_mainPageSetting.hJianju = map["行间距"].toInt();
    m_mainPageSetting.ppi = map["分辨率"].toInt();
}
bool CServiceBackend::getTestPaperTittle(QString tittle)
{
    m_testPaperTittle = tittle;
    return true;
}
bool CServiceBackend::printTestPaper()
{
    //在桌面目录下新建一个文件夹，用于存放pdf文件
    QString dirPdf ="试卷";
    QDir dir(QDir::current());
    QString desk = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
    dir.cd(desk);
    if(dir.exists(dirPdf)){
        dir.cd(dirPdf);
    }
    else {
        dir.mkdir(dirPdf);
        dir.cd(dirPdf);
    }
    //创建pdf文件
    QFile pdfFile;
    pdfFile.setFileName(dir.path()+"/"+m_testPaperTittle+".pdf");
    if(pdfFile.exists())
        pdfFile.remove();
    if(!pdfFile.open(QIODevice::WriteOnly)){
        m_error= "创建PDF文件失败！请检查原文件是否关闭！";
        return false;
    }
    m_pdfWriter = new QPdfWriter(&pdfFile);
    //设置分辨率
    m_pdfWriter->setResolution(m_mainPageSetting.ppi);
    //设置纸张大小
    if(m_mainPageSetting.pageSize == "A3"){
        m_pdfWriter->setPageSize(QPageSize(QPageSize::A3));
    }else if(m_mainPageSetting.pageSize == "A4"){
        m_pdfWriter->setPageSize(QPageSize(QPageSize::A4));
    }
    else {
        m_pdfWriter->setPageSize(QPageSize(QPageSize::A4));
    }
    //设置页面方向
    if(m_mainPageSetting.islandScape)
        m_pdfWriter->setPageOrientation(QPageLayout::Landscape);//横向页面
    else
        m_pdfWriter->setPageOrientation(QPageLayout::Portrait);//纵向页面
    //设置奇偶页
    m_isOddPage = true ;//初始为奇数
    //设置页边距
    qreal hJianju = (qreal)m_mainPageSetting.hJianju/(qreal)72*(qreal)300;//行间距
    //设置页边距
    QMarginsF tempMargin = m_mainPageSetting.pageMarMargins;
    m_pdfWriter->setPageMargins(tempMargin,QPageLayout::Millimeter);//用毫米作为单位
    //设置绘制的起始位置
    m_xStart = 0;
    m_yStart = 0;
    //关闭上次的，重新启动
    m_pPainter->begin(m_pdfWriter);
    //先打印侧面信息
    QFontMetricsF metricTemp(m_mainPageSetting.hcFont);
    QSizeF sizeTemp;//打印区域
    //设置考生信息
    QString msgTemp = "单位:______________  姓名:_________  得分:_________";
    if(m_mainPageSetting.isZhuangDing){
        //获取页面大小
        double pageContextHeight = m_pdfWriter->height();//内高,单位pix
        //根据字体获取单行文本的宽度和高度
        m_pPainter->save();
        QPen pen(Qt::black,2,Qt::DashDotLine);
        m_pPainter->setPen(pen);
        m_pPainter->drawLine(0-50,0-m_mainPageSetting.pageMarMargins.top()*300/25.4,0-50,pageContextHeight+m_mainPageSetting.pageMarMargins.bottom()*300/25.4);
        m_pPainter->setFont(m_mainPageSetting.ksFont);
        m_pPainter->translate(0,pageContextHeight);
        m_pPainter->rotate(-90);//旋转90度
        //打印考生信息
        metricTemp = m_pPainter->fontMetrics();
        sizeTemp = metricTemp.size(Qt::TextSingleLine,msgTemp);
        QRectF ks_rect = QRectF(0,0-200,pageContextHeight,sizeTemp.height());
        m_pPainter->drawText(ks_rect,Qt::AlignCenter,msgTemp);
        //重置坐标系
        m_pPainter->resetTransform();
        m_pPainter->restore();
    }
    //打印试卷标题
    writeText(m_testPaperTittle,m_mainPageSetting.h1Font,hJianju,0,true,0);
    if(!m_mainPageSetting.isZhuangDing){//如果打印在标题下方
        writeText(msgTemp,m_mainPageSetting.ksFont,hJianju,hJianju+20,true,0);
    }
    //打印试题
    bool ret = writeQuestionOrAnswer(true,hJianju);
    if(!ret){
        return false;
    }
    //打印答案
    //新建一页
    if(m_mainPageSetting.isDoublePage){//如果是双面打印，则重新设置页面信息
        if(m_isOddPage){
            //当前为奇数页，则下一个为偶数页，需要更换左右边距
            tempMargin.setLeft(m_mainPageSetting.pageMarMargins.right());
            tempMargin.setRight(m_mainPageSetting.pageMarMargins.left());
        }
        m_pdfWriter->setPageMargins(tempMargin,QPageLayout::Millimeter);//用毫米作为单位
    }
    m_pdfWriter->newPage();
    m_yStart = 0;
    m_xStart = 0;
    //改变奇偶页信息
    m_isOddPage = !m_isOddPage;
    //打印答案标题
    writeText(m_testPaperTittle+"答案",m_mainPageSetting.h1Font,hJianju,0,true,0);
    ret = writeQuestionOrAnswer(false,hJianju);
    if(!ret){
        return false;
    }

    m_pPainter->end();
    return true;
}

void CServiceBackend::writeText(QString text,QFont font,qreal hJianju,qreal topMargin, bool isCenter,int indentNum)
{
    //x,y存放的是上一次打印完毕后的位置，所以第一行开始就要加上页边距和字体高度
    //如果是新的一页开始，则需要判断是否为双面打印，如果是就需要重新设置页边距
    //    qDebug()<<"打印字体大小："<<font.family()<<font.pointSize();
    QMarginsF tempMargin = m_mainPageSetting.pageMarMargins;
    //获取页面大小
    qreal pageContextWidth = m_pdfWriter->width(); //内宽,单位pix
    qreal pageContextHeight = m_pdfWriter->height();//内高,单位pix
    //打印尺寸
    qreal pagePrintWidth;
    qreal pagePrintHeight = pageContextHeight;
    if(m_mainPageSetting.islandScape){
        //横向页面,需要分栏，打印区域需要去除中间间隔，默认使用右边距分割
        pagePrintWidth = (pageContextWidth-m_pdfWriter->margins().right/25.4*300)/2;
    }else
        pagePrintWidth = pageContextWidth;

    //根据字体获取单行文本的宽度和高度，字体发生改变以后都要重新调用，获取字符度量信息，用于计算文本宽高等信息
    QFontMetricsF metricTemp(font);//这种方法不准确
    m_pPainter->setFont(font);
    metricTemp = m_pPainter->fontMetrics();
    //调整文本信息,分行打印
    QStringList printText = text.split('\n');
    //去除空白项
    printText = printText.filter(QRegExp("\\S"));

    //保存单行文本的宽高尺寸，便于后续分解
    QSizeF sizeTemp ;
    QRectF recTemp;//单行文本的打印区域
    //开始打印
    QString msgTemp;//暂存需要打印的单行文本
    for(int i=0;i<printText.size();i++){
        msgTemp = printText.at(i);
        msgTemp = QString(indentNum*2,' ')+msgTemp;//通过添加空格，实现首行缩进
        //判断要打印几行
        sizeTemp = metricTemp.size(Qt::TextSingleLine,msgTemp);
        int hangNum = qCeil(sizeTemp.width()/pagePrintWidth);
        for(int j = 0;j<hangNum;j++){
            int tempHJianju = 0;
            //判断打印行是否超页面
            if(i==0&&j==0){
                //第一行
                tempHJianju = topMargin;
            }
            else
                tempHJianju = hJianju;
            //设置打印起始位置
            if(m_yStart+sizeTemp.height()+tempHJianju>pagePrintHeight){//处理超页
                if(m_mainPageSetting.islandScape ){
                    //横向页面，自动分两栏
                    if(m_xStart ==0){
                        //换到右边栏
                        m_xStart = pagePrintWidth+m_pdfWriter->margins().right/25.4*300;
                        m_yStart = 0;
                    }else{
                        //已经用完第二栏，需要新建页面
                        if(m_mainPageSetting.isDoublePage){//如果是双面打印，则重新设置页面信息
                            if(m_isOddPage){
                                //当前为奇数页，则下一个为偶数页，需要更换左右边距
                                tempMargin.setLeft(m_mainPageSetting.pageMarMargins.right());
                                tempMargin.setRight(m_mainPageSetting.pageMarMargins.left());
                            }
                            m_pdfWriter->setPageMargins(tempMargin,QPageLayout::Millimeter);//用毫米作为单位
                        }
                        m_pdfWriter->newPage();
                        m_yStart = 0;
                        m_xStart = 0;
                        //改变奇偶页信息
                        m_isOddPage = !m_isOddPage;
                    }
                }else{
                    //纵向页面需要新建页面
                    if(m_mainPageSetting.isDoublePage){//如果是双面打印，则重新设置页面信息
                        //左右边距需要更换
                        if(m_isOddPage){
                            //当前为奇数页，则下一个为偶数页，需要更换左右边距
                            tempMargin.setLeft(m_mainPageSetting.pageMarMargins.right());
                            tempMargin.setRight(m_mainPageSetting.pageMarMargins.left());
                        }
                        m_pdfWriter->setPageMargins(tempMargin,QPageLayout::Millimeter);//用毫米作为单位
                    }
                    m_pdfWriter->newPage();
                    m_yStart = 0;
                    //改变奇偶页信息
                    m_isOddPage = !m_isOddPage;
                }
            }else{
                m_yStart += tempHJianju;
            }
            //开始打印
            QString leftStr = metricTemp.elidedText(msgTemp,Qt::ElideRight,pagePrintWidth);
            int leftNum = leftStr.length();//获取可打印字符串长度
            recTemp = QRectF(m_xStart,m_yStart,pagePrintWidth,sizeTemp.height());
//            qDebug()<<"打印文本："<<msgTemp<<pagePrintWidth<<m_pdfWriter->margins().right/25.4*300;
            if(!isCenter)
                m_pPainter->drawText(recTemp,Qt::AlignLeft,msgTemp.left(leftNum));
            else
                m_pPainter->drawText(recTemp,Qt::AlignCenter,msgTemp.left(leftNum));
            //打印位置向下移动一个字符高度
            m_yStart = m_yStart+sizeTemp.height();
            //获取剩下的字符串
            msgTemp = msgTemp.right(msgTemp.length()-leftNum);
        }
    }
}

void CServiceBackend::xiPaiVector(QVector<int> *vector)
{
    if(vector->size()>=2)
    {
        srand(time(NULL));
        for(int i = vector->size()-1;i>0;i--){
            int j = rand()%(i+1);
            vector->swapItemsAt(i,j);
        }
    }
}

bool CServiceBackend::writeQuestionOrAnswer(bool isQuestion,qreal hJianju)
{
    int tiXingXuhao =0;//用来保存题型序号
    SetMessge setMessageTemp;
    QString msgTemp;
    QFontMetricsF metricTemp(m_mainPageSetting.hcFont);
    QSizeF sizeTemp;
    for(int i =0;i<m_testPaperSet.size();i++){
        setMessageTemp.m_TestName = m_testPaperSet.at(i).m_TestName;
        setMessageTemp.m_testNum =  m_testPaperSet.at(i).m_testNum;
        setMessageTemp.m_fenZhi = m_testPaperSet.at(i).m_fenZhi;
        QStringList xuhaoList = {"一","二","三","四","五","六","七","八","九","十"};
        int msgColum;//题型所在列,从0开始编号的,第三列为试题信息
        if(isQuestion){
            msgColum = 3;
        }else
            msgColum = 5;
        QVector<int> *tiXingListTemp=&m_dTiXingList;//题型列表
        if(setMessageTemp.m_testNum !=0 && setMessageTemp.m_fenZhi!=0){//数量和分值都不能为零
            //打印一级标题
            msgTemp = xuhaoList.at(tiXingXuhao)+"、"+setMessageTemp.m_TestName+"（每题"+QString::number(setMessageTemp.m_fenZhi)+"分）";
            tiXingXuhao += 1;
            //更新题型列表
            if(setMessageTemp.m_TestName == "单选题")
                tiXingListTemp = &m_dTiXingList;
            else if(setMessageTemp.m_TestName == "多选题")
                tiXingListTemp = &m_dxTiXingList;
            else if(setMessageTemp.m_TestName == "判断题")
                tiXingListTemp = &m_pTiXingList;
            else if(setMessageTemp.m_TestName == "填空题")
                tiXingListTemp = &m_tTiXingList;
            else if(setMessageTemp.m_TestName == "简答题")
                tiXingListTemp = &m_jTiXingList;
            //打印标题
            m_pPainter->setFont(m_mainPageSetting.h2Font);
            metricTemp = m_pPainter->fontMetrics();//字体发生变化以后要重新获取一次
            sizeTemp = metricTemp.size(Qt::TextSingleLine,msgTemp);
            writeText(msgTemp,m_mainPageSetting.h2Font,hJianju,hJianju,false,2);
            //打印试题
            //随机抽取
            if(isQuestion)
                xiPaiVector(tiXingListTemp);//试题洗牌，答案不用洗牌，否则答案不正确
            if(m_sheet){
                for(int a=0; a<setMessageTemp.m_testNum;a++){
                    int tempTiHao = a%tiXingListTemp->size();//如果数量超过题库数量，则取模选题
                    QString tiMuTemp;
                    if(m_sheet->cellType(tiXingListTemp->at(tempTiHao),msgColum)==CELLTYPE_STRING){
                        const wchar_t* tiMu = m_sheet->readStr(tiXingListTemp->at(tempTiHao),msgColum);
                        tiMuTemp = QString::fromStdWString(tiMu);
                    }
                    else if(m_sheet->cellType(tiXingListTemp->at(tempTiHao),msgColum)== CELLTYPE_NUMBER){
                        double tiMu = m_sheet->readNum(tiXingListTemp->at(tempTiHao),msgColum);
                        tiMuTemp = QString::number(tiMu,'f');
                    }
                    else{
                        m_error= "第"+QString::number(tiXingListTemp->at(tempTiHao)+1)+"行，第"+QString::number(msgColum+1)+"列数据类型错误,必须为数字或者字符串";
                        qDebug()<<"读取数据错误："<<m_error;
                        return false;
                    }
                    tiMuTemp = QString::number(a+1)+"、"+tiMuTemp;//题目前面添加题号
                    writeText(tiMuTemp,m_mainPageSetting.hcFont,hJianju,hJianju,false,2);
                    if(setMessageTemp.m_TestName == "简答题" && isQuestion){//简答题试题
                        //简答题还要上答案，确保留下答题空间；只需要把颜色换成透明
                        QPen oldPen = m_pPainter->pen();
                        m_pPainter->setPen(QColor("transparent"));//使用透明字
                        QString daAnTemp;
                        if(m_sheet->cellType(tiXingListTemp->at(tempTiHao),msgColum+2)==CELLTYPE_STRING){
                            const wchar_t* daAn = m_sheet->readStr(tiXingListTemp->at(tempTiHao),msgColum+2);
                            daAnTemp = QString::fromStdWString(daAn);
                        }
                        else if(m_sheet->cellType(tiXingListTemp->at(tempTiHao),msgColum+2)== CELLTYPE_NUMBER){
                            double daAn = m_sheet->readNum(tiXingListTemp->at(tempTiHao),msgColum+2);
                            daAnTemp = QString::number(daAn,'f');
                        }else{
                            m_error= "第"+QString::number(tiXingListTemp->at(tempTiHao)+1)+"行，第"+QString::number(msgColum+3)+"列数据类型错误,必须为数字或者字符串";
                            qDebug()<<"试题："<<m_error;
                            return false;
                        }
                        daAnTemp += "\n空\n空\n空";//多空3行避免不够,后面加空字，避免全空行会被自动去除
                        writeText(daAnTemp,m_mainPageSetting.hcFont,hJianju,hJianju,false,2);
                        m_pPainter->setPen(oldPen);
                    }
                }
            }else {
                m_error = "无法读取Excel文件！";
                return false;
            }

        }
    }
    return true;
}


